package org.hoyi.microservice;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.Servlet;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext;
import org.hoyi.DB.conf.HOYIConf;
import org.hoyi.DB.ctrl.Console;
import org.hoyi.DB.util.ConfigUtil;
import org.hoyi.ctrls.sys.sh.ShellCtrls;
import org.hoyi.dishop.Hoyipage;
import org.hoyi.dispatchs.DispatcherServlet;
import org.hoyi.servmotions.refreshpage_motion;
import org.hoyi.sessionlisten.SessionIniter;
import org.hoyi.util.HTMLUtils;
import org.hoyi.util.HttpRequest;
import org.hoyi.util.StreamUtils;
import org.hoyi.websocket.HoyiWebSocketHandler;
import org.hoyi.websocket.HoyiWebSocketListener;
import org.hoyi.websocket.WebSocketConf;
import org.yaml.snakeyaml.Yaml;

import net.sf.json.JSONObject;

/**
 * 
 * 1. 负载均衡用nginx直接配置，断熔器可以由nginx处理. 2. 模式1，直接启动端口，发送服务ID给调度注册，
 * 模式2，直接发送服务ID给调度端，由调度端发送可用端口给服务端，并启动服务。 当未收到调度端的回复时，自动隔固定时间请求，可以以次数和时间来做请求限制。
 * 3. 当想重新启动服务时，可以由服务端发起复制服务端的请求，并启动当前服务端。 4. 就要求每台调度服务器需要一个nginx。
 * 
 * 关键流程
 * 
 * 1. 类型： serviceDispatcher Server, serviceProvider Server, nginx Server
 * 
 * 2. 启动1:
 * HoyiCloudApplication.Start("ServiceID", port)
 * HoyiCloudApplication.Start(port)
 * 
 * 3. 启动2: HoyiCloudApplication.ReqProvide("ServiceID") 由调度端分配Port.
 * HoyiCloudApplication.ReqProvide("ServiceID", "ParentServiceID")
 * 
 * 4. 增加服务： 调度端：后台界面->选择服务->选择扩充->自动增加了对应的几个服务上来。 本地端：得到复制命令->复制服务文件->启动服务
 * 【需要服务复制的考虑留一个备份，谨防执行中的文件复制失败。】
 * 
 * 5. 调度端：需要安装nginx并且配置好命令行执行,Web 服务端和调度端需要配置操作系统类型、nginx.conf路径，
 * 这个可以默认提供几个系统的路径，可以自己修改。 服务提供端需要配置：文件复制源地址，文件复制目标地址，文件夹名规则，服务启动命令。
 * 
 * 6. 调度关系: 
 * sdispacher->nginx->nginx->sprovider 
 * sdispacher->nginx->sprovider
 * sdispacher->nginx->sdispatcher->nginx->sprovider
 * 
 * 服务提供端总在最后一层。
 * 
 * 启动实例：
 * 
 * public class JettyServer { 
 * 	public static void main(String[] args) {
 * 		HoyiCloudApplication.Start(); //HoyiCloudApplication.Start(8081); 
 * 	} 
 * }
 * 
 * 
 * 启动websocket服务器实例：
 * 
 * IMsgListener请参照 hoyi-webs/src/org/hoyi/websocket/HoyiWebSocketListener.java类.
 * 
 * public class IMServerRunner {

	public static void main(String[] args) {

		HoyiWebSocketHandler _websocketHandler = new HoyiWebSocketHandler("/ws", IMsgListener.class, 30000);
		WebSocketConf.WebSocketPathHandler.put(_websocketHandler.Req_Path, _websocketHandler);
		
		HoyiWebSocketHandler _websocketHandler2 = new HoyiWebSocketHandler("/ws2", IMsgListener2.class, 30000);
		WebSocketConf.WebSocketPathHandler.put(_websocketHandler2.Req_Path, _websocketHandler2);
		
		HoyiCloudApplication.Start(80, ".", new DispatcherServlet(), true);
	}
}
 * 
 * 
 * @param args
 */
public class HoyiCloudApplication {
	
	/**
	 * 是否通过HoyiCloudAPP启动的.
	 */
	public static boolean CloudAppStarting = false;

	/**
	 * 打开开发模式，不做混存处理，
	 */
	public static boolean DebugMode = false;
	/**
	 * 在编写页面的时候，自动刷新页面
	 */
	public static boolean AutoRefreshPage = false;
	/**
	 * 自动刷新页面的秒数.
	 */
	public static int AutoRefreshSeconds = 3;
	
	/**
	 * 是否监听页面是最新的，如果为true,则页面监听页面是否最新的，监听内容包括HTML,Java等，
	 * 服务有重启的话，则自动刷新页面.
	 */
	public static boolean Motion_Page_Newest = false;
	/**
	 * 监听服务时间，单位毫秒
	 */
	public static int Motion_Page_Newest_millons = 300;
	/**
	 * 是否输出Motion_Page的日志.
	 */
	public static boolean Motion_Page_Newest_Console_Log = false;
	
	/**
	 * 是否打开本地的WebRoot;
	 */
	public static boolean OpenLocalWebRoot = false;
	/**
	 * 当在IDEA调试的时候，打开了OpenDebug,但是IDEA不会动态打包到pack目录内，所以当你改了HTML的时候就会失效，
	 * 这个时候，就可以将WebRootPath设置到你的系统目录内，这样修改了页面的时候就不用每次都重启了.
	 * 这个目录为WebRoot上一级目录，不带WebRoot,且以/结尾
	 */
	public static String WebRootPath = "";

	/**
	 * 请求的端口.
	 */
	public static int REQ_PORT = -1;

	/**
	 * 是否需要调度端分配端口.
	 */
	public static String NEED_PORT;

	public static HoyiServiceConfig hoyiconfig;
	
	/**
	 * 系统启动的时间.
	 */
	public static long cloud_staringtime = -1;

	/**
	 * 服务器注册的可分配端口，请求端口的时候自动分配给本地， Map<IP, List<Port>> 为统一标准，localhost和127.0.0.1
	 * 统一转换为localhost
	 */
	private static Map<String, List<String>> PORT_BAKS = new HashMap<>();

	/**
	 * 已经使用了的端口列表. 自己提交，自己启动的服务会注册到已使用的端口列表内.
	 */
	private static Map<String, List<String>> PORT_USED = new HashMap<>();

	/**
	 * 是否已经加载了Config.
	 */
	public static boolean ConfigLoaded = false;
	
	public static void LoadConfig() {
		if (!ConfigLoaded) {
			try {
				Yaml yaml = new Yaml();
				File files = null;
				if(ConfigUtil.OpenOuterConfig) {
					if(ConfigUtil.OuterConfigPath.trim().length() > 0) {
						files = new File(ConfigUtil.OuterConfigPath);
					}else {
						files = new File("");
						files = new File(files.getAbsoluteFile() + "/config");
					}
				}else if(ConfigUtil.Open_HostRoot_Config) {
					
					// 从外部路径读
					files = new File("");
					files = new File(files.getAbsoluteFile() + "/config");
				}
				if(files != null){
					String path = files.getAbsolutePath() + "/hoyi-service.yml";
//					byte[] configbts = StreamUtils.Create().ReaderResource(path);
					Console.Info("begin Load config Path:" + path);
					byte[] configbts = StreamUtils.Create().ReadLocalFileResource(path);
					String configcontent = new String(configbts, "UTF-8");
					Console.Info("Config:" + configcontent);
					hoyiconfig = yaml.loadAs(configcontent, HoyiServiceConfig.class);
				}else{
					hoyiconfig = yaml.loadAs(HoyiCloudApplication.class.getResourceAsStream("/config/hoyi-service.yml"),
							HoyiServiceConfig.class);
				}
				if (hoyiconfig == null)
					hoyiconfig = new HoyiServiceConfig();
				Console.Info(hoyiconfig.toString());
			} catch (Exception e) {
				hoyiconfig = new HoyiServiceConfig();
				Console.Info("No Hoyi Cloud Configureation File!");
			}
			ConfigLoaded = true;
		}
	}

	/**
	 * 监控页面是否有修改，有修改则自动刷新.
	 * 设置了OpenDebug,也就是DebugMode为true的时候生效.
	 * 开启监听前，请保证调用了loadconfig,且配置了OpenDebugPath.,否则不生效.
	 */
	public static void BeginMotionPageModi() {
		if(HoyiCloudApplication.Motion_Page_Newest) {
			String OpenDebugPath = HoyiCloudApplication.hoyiconfig.getHOYI().getOrDefault("OpenDebugPath", "NoNeed");
			if(!OpenDebugPath.equals("NoNeed")) {
				String[] _paths = {OpenDebugPath};
			    refreshpage_motion.Begin_Motion(_paths);
			    
			}
		}
	}
	/**
	 * 9.1.03 将第二个参数的./WebContent 改为 .
	 */
	public static void Start() {
		Start(REQ_PORT, ".", new DispatcherServlet());
	}
	/**
	 * 9.1.03 将第二个参数的./WebContent 改为 .
	 */
	public static void Start(int port) {
		Start(port, ".", new DispatcherServlet());
	}
	/**
	 * 启动前关闭可能占用的端口
	 * windows未测试，慎用.
	 * @param port
	 */
	public static void StopPort(int port) {
		ShellCtrls _shell = new ShellCtrls();
		String result = _shell.StopPort(port);
		Console.Info("port:" + port + " stoped , ret:" + result);
	}
	/**
	 * 如果端口运行中，则关闭端口.
	 * windows未测试，慎用.
	 * @param port
	 */
	public static void StopPortIfRunning(int port) {
		ShellCtrls _shell = new ShellCtrls();
		Console.Info("OS NAME:" + _shell.GetOsName());
		boolean isrunning = _shell.PortisRuning(port);
		if(isrunning) {
			StopPort(port);
		}
	}
	/**
	 * 启动
	 * @param port
	 * @param webcontent	新项目统一用 ".",旧的Java Web 项目设置为:"./WebContent"
	 */
	public static void Start(int port, String webcontent){

		Start(port, webcontent, new DispatcherServlet());
	}
	
	/**
	 * 打开本地WebRoot目录.
	 * @param _local_webRootPath
	 */
	public static void OpenLocalWebRoot(String _local_webRootPath) {
		OpenLocalWebRoot = true;
		WebRootPath = _local_webRootPath;
	}
	/**
	 * 每次启动都重启.
	 * windows未测试，慎用.
	 * @param port
	 */
//	public static void StartAuto(int port) {
//		StopPortIfRunning(port);
//		Start(port, ".");
//	}
	/**
	 * 打开外部配置文件，
	 * 提供部署到服务器的时候，不需要暴露用户名密码，
	 * 传输代码到外部服务器时候，不需要泄露更多用户名密码等数据。
	 * 
	 * @param outerconfigpath
	 */
	public static void OpenOutConfig(String outerconfigpath) {
		ConfigUtil.OpenOuterConfig = true;
		ConfigUtil.OuterConfigPath = outerconfigpath;
	}
	/**
	 * 打开本地通用文件地址，并设置路径.
	 * 
	 * 通用文件类型为:图片,css,js,woff,ttf,等.
	 * 
	 * @param _local_custom_file_path
	 */
	public static void OpenLocalCustomFile(String _local_custom_file_path) {
		HOYIConf.OpenLocalCustomFile(_local_custom_file_path);
	}
	
	/**
	 * 从启动jar包同目录下读取config.
	 * 这样再同目录下直接读取config内的配置文件就OK，
	 * 同时方便修改配置文件，不好的地方就是配置文件直接暴露再硬盘。
	 */
	public static void OpenRootConfig() {
		ConfigUtil.Open_HostRoot_Config = true;
	}
	
	/**
	 * 打开调试模式，不会缓存文件、HTML，修改的类会动态加载，不会从内存中读取，
	 * 部署的时候，请不要打开这个选项.
	 * @param hotloadpath
	 */
	public static void OpenDebug() {
		HoyiCloudApplication.DebugMode = true;
		
		Hoyipage.OpenCacheHTML = false;
		HTMLUtils.OpenHTMLCache = false;
		// 关掉页面的Mapping.
		HOYIConf.PageCache = false;
	}
	
	/**
	 * 打开调试，并设置本地.hoyip.html加载路径。
	 * 主要用于IDEA工具调试时候无法实施发布HTML文件而定的.
	 * @param _local_webRoot_path
	 */
	public static void OpenDebug(String _local_webRoot_path) {
		OpenDebug();
		OpenLocalWebRoot(_local_webRoot_path);
	}
	
	/**
	 * 打开自动刷新页面，
	 * 打开后，页面会每个refreshsec秒自动刷新.
	 * @param refreshsec 自动刷新的秒数.
	 */
	public static void OpenAutoRefresh(int refreshsec) {
		HoyiCloudApplication.AutoRefreshSeconds = refreshsec;
		HoyiCloudApplication.AutoRefreshPage = true;
	}
	
	/**
	 * 启动服务的Server.
	 */
	private static Server server = null;
	/**
	 * 获取Jetty服务器对象.
	 * @return
	 */
	public static Server getServer() {
		return server;
	}
	/**
	 * 启动服务.
	 * @param port				启动的端口
	 * @param startservlet		启动的Servlet.
	 */
	public static void Start(int port,  Servlet startservlet) {
		Start(port, ".", startservlet);
	}
	
	/**
	 * 启动Hoyi服务.
	 * @param port			端口
	 * @param webcontent	资源文件路径，默认为 ".",旧的Java Web项目，可将此项设置为：./WebContent,因为旧项目的目录位置不同。
	 * 						因Hoyi9.1.02以后的版本支持HOYIConf.OpenLocalCustomFile(_local_custom_file_path);
	 * 						来设置本地目录读取，所以 webcontent这个方法亦可弃用，保留这是为了支持旧项目及支持向后兼容。
	 * @param startservlet  处理web的servlet.
	 */
	public static void Start(int port, String webcontent, Servlet startservlet) {
		Start(port, webcontent, startservlet, false, true);
	}
	
	/**
	 * 启动Hoyi服务.
	 * @param port			端口
	 * @param webcontent	资源文件路径，默认为 ".",旧的Java Web项目，可将此项设置为：./WebContent,因为旧项目的目录位置不同。
	 * 						因Hoyi9.1.02以后的版本支持HOYIConf.OpenLocalCustomFile(_local_custom_file_path);
	 * 						来设置本地目录读取，所以 webcontent这个方法亦可弃用，保留这是为了支持旧项目及支持向后兼容。
	 * @param startservlet  处理web的servlet.
	 * @param OpenWebSocket 是否打开websocket服务器.默认不打开.
	 * 						打开websocket方法如下：
							创建 		HoyiWebSocketHandler _websocketHandler = new HoyiWebSocketHandler("/ws", MyWebSocketListener.class, 30000);
							添加			WebSocket路径. WebSocketConf.WebSocketPathHandler.Add(_websocketHandler.Req_Path, _websocketHandler);
	 * 						启动服务		HoyiCloudApplication.Start(Port)
	 */
	public static void Start(int port, String webcontent, Servlet startservlet, boolean OpenWebSocket) {
		Start(port, webcontent, startservlet, OpenWebSocket, true);
	}
	
	/**
	 * 启动Hoyi服务.
	 * @param port			端口
	 * @param webcontent	资源文件路径，默认为 ".",旧的Java Web项目，可将此项设置为：./WebContent,因为旧项目的目录位置不同。
	 * 						因Hoyi9.1.02以后的版本支持HOYIConf.OpenLocalCustomFile(_local_custom_file_path);
	 * 						来设置本地目录读取，所以 webcontent这个方法亦可弃用，保留这是为了支持旧项目及支持向后兼容。
	 * @param startservlet  处理web的servlet.
	 * @param OpenWebSocket 是否打开websocket服务，默认不打开.
	 * 						打开websocket方法如下：
							创建 		HoyiWebSocketHandler _websocketHandler = new HoyiWebSocketHandler("/ws", MyWebSocketListener.class, 30000);
							添加			WebSocket路径. WebSocketConf.WebSocketPathHandler.Add(_websocketHandler.Req_Path, _websocketHandler);
	 * 						启动服务		HoyiCloudApplication.Start(Port)
	 * @param OpenWebServer 是否打开web服务器，默认为true.
	 * 						
	 */
	public static void Start(int port, String webcontent, Servlet startservlet, boolean OpenWebSocket, boolean OpenWebServer) {
		
		HoyiCloudApplication.cloud_staringtime = System.currentTimeMillis();
		HoyiCloudApplication.CloudAppStarting = true;
		LoadConfig();
		NEED_PORT = hoyiconfig.getHOYI().getOrDefault("NEED-PORT", "false");
		// 服务类型
		String SERVICETYPE = hoyiconfig.getSERVICE().getOrDefault("SERVICE-TYPE", "PROVIDER");
		// 调度地址
		String DISPATCHURL = hoyiconfig.getSERVICE().get("DISPATCHER-URL");

		String SERVICEID = hoyiconfig.getSERVICE().get("SERVICE-ID");
		String HOST = hoyiconfig.getHOYI().get("HOST");
		System.out.println("DISPATCHER-URL:" + DISPATCHURL);

		if (NEED_PORT.trim().toUpperCase().equals("TRUE")) {
			// 如果需要由服务器分配端口。
			System.out.println("Get Start ServicePort:" + DISPATCHURL + "index/GetStartPort.html");
			String PORT_BAK = hoyiconfig.getHOYI().get("PORT-BAK");
			HttpRequest request = new HttpRequest();
			String ret;
			try {
				ret = request.sendPost(DISPATCHURL + "index/GetStartPort.html",
						"serviceid=" + SERVICEID + "&host=" + HOST + "&portbaks=" + PORT_BAK);
				Console.Info("ERT:" + ret);
				JSONObject obj = JSONObject.fromObject(ret);
				String sgetport = obj.get("data").toString();

				Console.Info("Register Service:" + ret);
				if (sgetport != null && sgetport.toString().length() > 0) {
					// 服务器分配了端口，开始启动。
					REQ_PORT = Integer.parseInt(sgetport.toString());
				} else {
					Console.Info("未能分配启动端口，关闭服务"); // 这里后续可以做成重新发起申请
					return;
				}
			} catch (UnsupportedEncodingException e) {
				Console.Error("Getstartport error:" + e.getMessage());
			}
		}else {
			if (port == -1) {
				// 读取端口，未配置用默认.
				REQ_PORT = Integer.parseInt(hoyiconfig.getHOYI().getOrDefault("PORT", "8080"));
			}else {
				REQ_PORT = port;
			}
			Console.Info("port:" + REQ_PORT);
		}
		
		BeginMotionPageModi();

		if ("PROVIDER".equals(SERVICETYPE) && DISPATCHURL != null && DISPATCHURL.trim().length() > 1) {
			// 如果是服务提供者，而且调度地址不为空的话，则发起调度注册.
			System.out.println("Register Service URL:" + DISPATCHURL + "index/RegisterService.html");

			HttpRequest request = new HttpRequest();
			try {
				String ret = request.sendPost(DISPATCHURL + "index/RegisterService.html",
						"serviceid=" + SERVICEID + "&host=" + HOST + "&port=" + REQ_PORT);
				Console.Info("Register Service:" + ret);
			} catch (UnsupportedEncodingException e) {
				Console.Info("Register Service:" + e.getMessage());
			}
		}
		try {
			Console.Info("Begin Server:");
			if(webcontent.equals("./WebContent")) {
				// java web项目， 需要webcontent.  需要  ./WebContent
				// 新项目中请忽略这里的代码.
				
				// 完美运行.start
				InetSocketAddress address = new InetSocketAddress(REQ_PORT);
				server = new Server(address);
				
				WebAppContext webAppContext = new WebAppContext();
				webAppContext.setContextPath("/");
	
				Console.Info("Set Web Content: WebContent:");
				File resDir = new File(webcontent);
				webAppContext.setResourceBase(resDir.getCanonicalPath());
				webAppContext.setConfigurationDiscovered(true);
				webAppContext.setParentLoaderPriority(true);
				server.setHandler(webAppContext);
				
				
				Console.Info("Begin Server Finished:");
				server.start();
				server.join();
				// 完美运行.end
			}else {
				// java 非web项目， 不需要webcontent.
				Console.Info("Start Jerry Server.");

				InetSocketAddress address = new InetSocketAddress(REQ_PORT);
				server = new Server(address);

				ContextHandlerCollection context = new ContextHandlerCollection();
				/*	Web Socket Server Start. */

				// 如果打开WebSocket Server
				if(OpenWebSocket) {
					// 这里如果要加多个处理方法，你要怎么做？
					
					// 使用方法
					// 创建 HoyiWebSocketHandler _websocketHandler = new HoyiWebSocketHandler("/ws", MyWebSocketListener.class, 30000);
					// 添加WebSocket路径. WebSocketConf.WebSocketPathHandler.Add(_websocketHandler.Req_Path, _websocketHandler);
					// 
					
					for (String _req_path : WebSocketConf.WebSocketPathHandler.keySet()) {
						HoyiWebSocketHandler _websocketHandler = WebSocketConf.WebSocketPathHandler.get(_req_path);
						ContextHandler contextHandler = new ContextHandler();
						contextHandler.setContextPath(_websocketHandler.Req_Path);
						contextHandler.setHandler(_websocketHandler);
						context.addHandler(contextHandler);
					}
					
					Console.Info("Websocket Server Started!~");
				}
				
				/*  Web Socket Server End*/
			
				/*  Web Application Server End*/
				// 如果打开WebServer 服务. 为false的话，如果同时打开websocket,则独立为websocket服务器.
				if(OpenWebServer) {
					WebAppContext webAppContext = new WebAppContext();
					webAppContext.setContextPath("/");
					webAppContext.setResourceBase(".");
					webAppContext.addServlet(new ServletHolder(startservlet), "/*");
					webAppContext.setConfigurationDiscovered(true);
					webAppContext.setParentLoaderPriority(true);

					context.addHandler(webAppContext);
				}
				
//				备留方法.
//				webAppContext.addServlet(new ServletHolder(new DispatcherServlet()), "/*");// + HOYIConf.Suffix);
//				WebAppClassLoader classLoader = new WebAppClassLoader(webAppContext);
//				webAppContext.setClassLoader(classLoader);
				
				// 启动websocket 和 webserver两个服务器的方法. websocket 使用OK.
				server.setHandler(context);
				
				//只启动app web server的方法
//				server.setHandler(webAppContext);
				
				/*  Web Application Server End*/
				
				Console.Info("Start Server Finished.");
				
				SessionIniter.getInstance().contextInitialized();
			}
			
			server.start();
			server.join();
		} catch (Exception e) {
			Stop();
		}
	}
	/**
	 * 停止服务器.
	 */
	public static void Stop() {
		Console.Error("Application Closed:");
		try {
			SessionIniter.getInstance().contextDestroyed();
		} catch (Exception e) {
			Console.Error(e);
		}
		try {
			if(server != null) {
				//server.setStopAtShutdown(true);
				server.stop();
			}
		} catch (Exception e1) {
			Console.Error(e1);
		}
	}
	/**
	 * 重启服务.
	 */
	public static void Restart() {
		try {
			Console.Info("Server Restarted");
			WebAppContext context = (WebAppContext)server.getHandler();
	        context.stop();
	        WebAppClassLoader classLoader = new WebAppClassLoader(context);
	        context.setClassLoader(classLoader);
	        context.start();
	        
		} catch (Exception e) {
			Console.Error("Restart Error:" + e.getMessage());
		}
	}

	public static Map<String, List<String>> getPORT_BAKS() {
		return PORT_BAKS;
	}

	public static void setPORT_BAKS(Map<String, List<String>> pORT_BAKS) {
		PORT_BAKS = pORT_BAKS;
	}

	public static Map<String, List<String>> getPORT_USED() {
		return PORT_USED;
	}

	public static void setPORT_USED(Map<String, List<String>> pORT_USED) {
		PORT_USED = pORT_USED;
	}

	/**
	 * 添加可分配的启动端口。
	 * 
	 * @param host
	 * @param port
	 */
	public static void AddBAKPorts(String host, String port) {
		List<String> ps = PORT_BAKS.get(host);
		if (ps != null) {
			ps.add(port);
			PORT_BAKS.remove(host);
			PORT_BAKS.put(host, ps);
		} else {
			ps = new ArrayList<>();
			ps.add(port);
			PORT_BAKS.put(host, ps);
		}
	}

	/**
	 * 将端口从可分配的启动端口列表内移除。
	 * 
	 * @param host
	 * @param port
	 */
	public static void RemoveBakPorts(String host, String port) {
		List<String> ps = PORT_BAKS.get(host);
		if (ps != null && ps.contains(port)) {
			ps.remove(port);
		}
		PORT_BAKS.remove(host);
		PORT_BAKS.put(host, ps);
	}

	/**
	 * 已经使用了的端口，同时需要从PORT_BAK内删掉
	 * 
	 * @param host
	 * @param port
	 */
	public static void UsedPort(String host, String port) {
		List<String> ps = PORT_USED.get(host);
		if (ps != null) {
			ps.add(port);
			PORT_USED.remove(host);
			PORT_USED.put(host, ps);
		} else {
			ps = new ArrayList<>();
			ps.add(port);
			PORT_USED.put(host, ps);
		}
		// 从可分配列表中移除.
		RemoveBakPorts(host, port);
	}
}
	